home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet multimedia / Muzyka / Edytory sampli (probek dzwieku) / ZynAddSubFX_2.2.0 / Setup_ZynAddSubFX-2.2.0.exe / source code / Misc / Bank.C next >
C/C++ Source or Header  |  2005-03-14  |  14KB  |  561 lines

  1. /*
  2.   ZynAddSubFX - a software synthesizer
  3.  
  4.   Bank.h - Instrument Bank 
  5.   Copyright (C) 2002-2005 Nasca Octavian Paul
  6.   Author: Nasca Octavian Paul
  7.  
  8.   This program is free software; you can redistribute it and/or modify
  9.   it under the terms of version 2 of the GNU General Public License 
  10.   as published by the Free Software Foundation.
  11.  
  12.   This program is distributed in the hope that it will be useful,
  13.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.   GNU General Public License (version 2) for more details.
  16.  
  17.   You should have received a copy of the GNU General Public License (version 2)
  18.   along with this program; if not, write to the Free Software Foundation,
  19.   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  20.  
  21. */
  22.  
  23. #include "Bank.h"
  24. #include <string.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <dirent.h>
  28. #include <sys/stat.h>
  29.  
  30. #include <sys/types.h>
  31. #include <fcntl.h>
  32. #include <unistd.h>
  33. #include <errno.h>
  34.  
  35. #include "Config.h"
  36.  
  37. #define INSTRUMENT_EXTENSION ".xiz"
  38.  
  39. //if this file exists into a directory, this make the directory to be considered as a bank, even if it not contains a instrument file
  40. #define FORCE_BANK_DIR_FILE ".bankdir"
  41.  
  42. Bank::Bank(){
  43.  
  44.  
  45.     ZERO(defaultinsname,PART_MAX_NAME_LEN);
  46.     snprintf(defaultinsname,PART_MAX_NAME_LEN,"%s"," ");
  47.         
  48.     for (int i=0;i<BANK_SIZE;i++){
  49.     ins[i].used=false;
  50.     ins[i].filename=NULL;
  51.     ins[i].info.PADsynth_used=false;
  52.     };
  53.     dirname=NULL;
  54.     clearbank();
  55.  
  56.  
  57.  
  58.     for (int i=0;i<MAX_NUM_BANKS;i++){
  59.     banks[i].dir=NULL;
  60.     banks[i].name=NULL;
  61.     };
  62.     
  63.     bankfiletitle=dirname;
  64.  
  65.     loadbank(config.cfg.currentBankDir);
  66.  
  67. };
  68.  
  69. Bank::~Bank(){
  70.     if (dirname!=NULL) {
  71.     sprintf(config.cfg.currentBankDir,"%s",dirname);
  72.     };
  73.     for (int i=0;i<MAX_NUM_BANKS;i++){
  74.     if (banks[i].dir!=NULL) delete (banks[i].dir);
  75.     if (banks[i].name!=NULL) delete (banks[i].name);
  76.     };
  77.  
  78.     clearbank();
  79. };
  80.  
  81. /*
  82.  * Get the name of an instrument from the bank
  83.  */
  84. char *Bank::getname (unsigned int ninstrument){
  85.     if (emptyslot(ninstrument)) return (defaultinsname);
  86.     return (ins[ninstrument].name);
  87. };
  88.  
  89. /*
  90.  * Get the numbered name of an instrument from the bank
  91.  */
  92. char *Bank::getnamenumbered (unsigned int ninstrument){
  93.     if (emptyslot(ninstrument)) return (defaultinsname);
  94.     snprintf(tmpinsname[ninstrument],PART_MAX_NAME_LEN+15,"%d. %s",ninstrument+1,getname(ninstrument));
  95.     return(tmpinsname[ninstrument]);
  96. };
  97.  
  98. /*
  99.  * Changes the name of an instrument (and the filename)
  100.  */
  101. void Bank::setname(unsigned int ninstrument,const char *newname,int newslot){
  102.     if (emptyslot(ninstrument)) return;
  103.     
  104.     char newfilename[1000+1],tmpfilename[100+1];
  105.     
  106.     ZERO(newfilename,1001);
  107.     ZERO(tmpfilename,101);
  108.     if (newslot>=0) snprintf(tmpfilename,100,"%4d-%s",newslot+1,newname);
  109.     else snprintf(tmpfilename,100,"%4d-%s",ninstrument+1,newname);
  110.     
  111.     //add the zeroes at the start of filename
  112.     for (int i=0;i<4;i++) if (tmpfilename[i]==' ') tmpfilename[i]='0';
  113.  
  114.     //make the filenames legal
  115.     for (int i=0;i<(int) strlen(tmpfilename);i++) {
  116.     char c=tmpfilename[i];
  117.     if ((c>='0')&&(c<='9')) continue;
  118.     if ((c>='A')&&(c<='Z')) continue;
  119.     if ((c>='a')&&(c<='z')) continue;
  120.     if ((c=='-')||(c==' ')) continue;
  121.     
  122.     tmpfilename[i]='_';
  123.     };
  124.  
  125.     snprintf(newfilename,1000,"%s/%s.xiz",dirname,tmpfilename);
  126.  
  127. //    printf("rename %s -> %s\n",ins[ninstrument].filename,newfilename);//////////////
  128.  
  129.     rename(ins[ninstrument].filename,newfilename);
  130.     if (ins[ninstrument].filename) delete(ins[ninstrument].filename);
  131.     ins[ninstrument].filename=new char[strlen(newfilename)+5];
  132.     snprintf(ins[ninstrument].filename,strlen(newfilename)+1,"%s",newfilename);
  133.     snprintf(ins[ninstrument].name,PART_MAX_NAME_LEN,"%s",&tmpfilename[5]);
  134.     
  135. };
  136.  
  137. /*
  138.  * Check if there is no instrument on a slot from the bank
  139.  */
  140. int Bank::emptyslot(unsigned int ninstrument){
  141.     if (ninstrument>=BANK_SIZE) return (1);
  142.     if (ins[ninstrument].filename==NULL) return(1);
  143.  
  144.     if (ins[ninstrument].used) return (0);
  145.     else return(1);
  146. };
  147.  
  148. /*
  149.  * Removes the instrument from the bank
  150.  */
  151. void Bank::clearslot(unsigned int ninstrument){
  152.     if (emptyslot(ninstrument)) return;
  153.     
  154. //    printf("remove  %s  \n",ins[ninstrument].filename);////////////////////////
  155.     
  156.     
  157.     remove(ins[ninstrument].filename);
  158.     deletefrombank(ninstrument);
  159. };
  160.  
  161. /*
  162.  * Save the instrument to a slot 
  163.  */
  164. void Bank::savetoslot(unsigned int ninstrument,Part *part){
  165.     clearslot(ninstrument);
  166.     
  167.     const int maxfilename=200;
  168.     char tmpfilename[maxfilename+20];
  169.     ZERO(tmpfilename,maxfilename+20);
  170.  
  171.     snprintf(tmpfilename,maxfilename,"%4d-%s",ninstrument+1,(char *)part->Pname);
  172.  
  173.     //add the zeroes at the start of filename
  174.     for (int i=0;i<4;i++) if (tmpfilename[i]==' ') tmpfilename[i]='0';
  175.     
  176.     //make the filenames legal
  177.     for (int i=0;i<(int)strlen(tmpfilename);i++) {
  178.     char c=tmpfilename[i];
  179.     if ((c>='0')&&(c<='9')) continue;
  180.     if ((c>='A')&&(c<='Z')) continue;
  181.     if ((c>='a')&&(c<='z')) continue;
  182.     if ((c=='-')||(c==' ')) continue;
  183.     
  184.     tmpfilename[i]='_';
  185.     };
  186.  
  187.     strncat(tmpfilename,".xiz",maxfilename+10);
  188.  
  189.     int fnsize=strlen(dirname)+strlen(tmpfilename)+10;
  190.     char *filename=new char[fnsize+4];
  191.     ZERO(filename,fnsize+2);
  192.  
  193.     snprintf(filename,fnsize,"%s/%s",dirname,tmpfilename);
  194.  
  195.     remove(filename);
  196.     part->saveXML(filename);
  197.     addtobank(ninstrument,tmpfilename,(char *) part->Pname);
  198.     
  199.     delete(filename);
  200. };
  201.  
  202. /*
  203.  * Loads the instrument from the bank
  204.  */
  205. void Bank::loadfromslot(unsigned int ninstrument,Part *part){
  206.     if (emptyslot(ninstrument)) return;
  207.     
  208.     part->defaultsinstrument();
  209.  
  210. //    printf("load:  %s\n",ins[ninstrument].filename);
  211.     
  212.     part->loadXMLinstrument(ins[ninstrument].filename);
  213.     
  214. };
  215.  
  216.  
  217. /*
  218.  * Makes current a bank directory
  219.  */
  220. int Bank::loadbank(const char *bankdirname){
  221.     DIR *dir=opendir(bankdirname);
  222.     clearbank();
  223.  
  224.     if (dir==NULL) return(-1);
  225.  
  226.     if (dirname!=NULL) delete(dirname);
  227.     dirname=new char[strlen(bankdirname)+1];
  228.     snprintf(dirname,strlen(bankdirname)+1,"%s",bankdirname);
  229.     
  230.     bankfiletitle=dirname;
  231.  
  232.    // printf("loadbank %s/\n",bankdirname);
  233.     struct dirent *fn;
  234.         
  235.     while ((fn=readdir(dir))){
  236.     const char *filename= fn->d_name;
  237.     
  238.     //sa verific daca e si extensia dorita
  239.     if (strstr(filename,INSTRUMENT_EXTENSION)==NULL) continue;
  240.     
  241.     //verify if the name is like this NNNN-name (where N is a digit)
  242.     int no=0;
  243.     unsigned int startname=0;
  244.     
  245.     for (unsigned int i=0;i<4;i++) {
  246.         if (strlen(filename)<=i) break;
  247.  
  248.         if ((filename[i]>='0')&&(filename[i]<='9')) {
  249.         no=no*10+(filename[i]-'0');
  250.         startname++;
  251.         };
  252.     };
  253.     
  254.     
  255.     if ((startname+1)<strlen(filename)) startname++;//to take out the "-"
  256.     
  257.     char name[PART_MAX_NAME_LEN+1]; 
  258.     ZERO(name,PART_MAX_NAME_LEN+1);
  259.     snprintf(name,PART_MAX_NAME_LEN,"%s",filename);
  260.     
  261.     //remove the file extension
  262.     for (int i=strlen(name)-1;i>=2;i--){
  263.         if (name[i]=='.') {
  264.         name[i]='\0';
  265.         break;
  266.         };
  267.     };
  268.     
  269.     if (no!=0){//the instrument position in the bank is found
  270.         addtobank(no-1,filename,&name[startname]);
  271.     } else {
  272.         addtobank(-1,filename,name);
  273.     };
  274.     
  275.     };
  276.     
  277.     
  278.     closedir(dir);
  279.     return(0);
  280. };
  281.  
  282. /*
  283.  * Makes a new bank, put it on a file and makes it current bank
  284.  */
  285. int Bank::newbank(const char *newbankdirname){
  286.     int result;
  287.     char tmpfilename[MAX_STRING_SIZE];
  288.     char bankdir[MAX_STRING_SIZE];
  289.     snprintf(bankdir,MAX_STRING_SIZE,"%s",config.cfg.bankRootDirList[0]);
  290.  
  291.     if (((bankdir[strlen(bankdir)-1])!='/')&&((bankdir[strlen(bankdir)-1])!='\\')){
  292.     strncat(bankdir,"/",MAX_STRING_SIZE);
  293.     };
  294.     strncat(bankdir,newbankdirname,MAX_STRING_SIZE);
  295. #ifdef OS_WINDOWS
  296.     result=mkdir(bankdir);
  297. #else
  298.     result=mkdir(bankdir,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  299. #endif
  300.     if (result<0) return(-1);
  301.  
  302.     snprintf(tmpfilename,MAX_STRING_SIZE,"%s/%s",bankdir,FORCE_BANK_DIR_FILE);
  303. //    printf("%s\n",tmpfilename);
  304.     FILE *tmpfile=fopen(tmpfilename,"w+");
  305.     fclose(tmpfile);
  306.     
  307.     return(loadbank(bankdir));
  308. };
  309.  
  310. /*
  311.  * Check if the bank is locked (i.e. the file opened was readonly)
  312.  */
  313. int Bank::locked(){
  314.     return(dirname==NULL);
  315. };
  316.  
  317. /*
  318.  * Swaps a slot with another
  319.  */
  320. void Bank::swapslot(unsigned int n1, unsigned int n2){
  321.     if ((n1==n2)||(locked())) return;
  322.     if (emptyslot(n1)&&(emptyslot(n2))) return;
  323.     if (emptyslot(n1)){//change n1 to n2 in order to make
  324.     int tmp=n2;n2=n1;n1=tmp;
  325.     };
  326.     
  327.     if (emptyslot(n2)){//this is just a movement from slot1 to slot2
  328.     setname(n1,getname(n1),n2);
  329.     ins[n2]=ins[n1];
  330.     ins[n1].used=false;
  331.     ins[n1].name[0]='\0';
  332.     ins[n1].filename=NULL;
  333.     ins[n1].info.PADsynth_used=0;
  334.     } else {//if both slots are used
  335.     if (strcmp(ins[n1].name,ins[n2].name)==0){//change the name of the second instrument if the name are equal
  336.         strncat(ins[n2].name,"2",PART_MAX_NAME_LEN);
  337.     };
  338.     setname(n1,getname(n1),n2);
  339.     setname(n2,getname(n2),n1);
  340.     ins_t tmp;
  341.     tmp.used=true;
  342.     strcpy(tmp.name,ins[n2].name);
  343.     char *tmpfilename=ins[n2].filename;
  344.     bool padsynth_used=ins[n2].info.PADsynth_used;
  345.     
  346.     ins[n2]=ins[n1];
  347.     strcpy(ins[n1].name,tmp.name);
  348.     ins[n1].filename=tmpfilename;
  349.     ins[n1].info.PADsynth_used=padsynth_used;
  350.     };
  351.     
  352. };
  353.  
  354.  
  355. //a helper function that compares 2 banks[] arrays
  356. int Bank_compar(const void *a,const void *b){
  357.     struct Bank::bankstruct *bank1= (Bank::bankstruct *)a;
  358.     struct Bank::bankstruct *bank2= (Bank::bankstruct *)b;
  359.     if (((bank1->name)==NULL)||((bank2->name)==NULL)) return(0);
  360.  
  361.     int result=strcasecmp(bank1->name,bank2->name);
  362.     return(result<0);
  363. };
  364.  
  365.  
  366. /*
  367.  * Re-scan for directories containing instrument banks
  368.  */
  369.  
  370. void Bank::rescanforbanks(){
  371.     for (int i=0;i<MAX_NUM_BANKS;i++){
  372.     if (banks[i].dir!=NULL) delete (banks[i].dir);
  373.     if (banks[i].name!=NULL) delete (banks[i].name);
  374.     banks[i].dir=NULL;
  375.     banks[i].name=NULL;
  376.     };
  377.  
  378.     for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) if (config.cfg.bankRootDirList[i]!=NULL) scanrootdir(config.cfg.bankRootDirList[i]);
  379.  
  380.     //sort the banks
  381.     for (int j=0;j<MAX_NUM_BANKS-1;j++){
  382.     for (int i=j+1;i<MAX_NUM_BANKS;i++){
  383.         if (Bank_compar(&banks[i],&banks[j])) {
  384.         char *tmpname=banks[i].name;
  385.         char *tmpdir=banks[i].dir;
  386.  
  387.         banks[i].name=banks[j].name;
  388.         banks[i].dir=banks[j].dir;
  389.  
  390.         banks[j].name=tmpname;
  391.         banks[j].dir=tmpdir;
  392.         
  393.         };
  394.     };
  395.     };
  396.     
  397.     //remove duplicate bank names
  398.     int dupl=0;
  399.     for (int j=0;j<MAX_NUM_BANKS-1;j++){
  400.     for (int i=j+1;i<MAX_NUM_BANKS;i++){
  401.         if ((banks[i].name==NULL)||(banks[j].name==NULL)) continue;
  402.         if (strcmp(banks[i].name,banks[j].name)==0) {//add a [1] to the first bankname and [n] to others
  403.             char *tmpname=banks[i].name;
  404.             banks[i].name=new char[strlen(tmpname)+100];
  405.             sprintf(banks[i].name,"%s[%d]",tmpname,dupl+2);
  406.             delete(tmpname);
  407.         
  408.         if (dupl==0){
  409.                 char *tmpname=banks[j].name;
  410.                 banks[j].name=new char[strlen(tmpname)+100];
  411.             sprintf(banks[j].name,"%s[1]",tmpname);
  412.                 delete(tmpname);
  413.         };
  414.         
  415.             dupl++;
  416.         } else dupl=0;
  417.     };
  418.     };
  419.     
  420. }; 
  421.  
  422.  
  423.  
  424. // private stuff
  425.  
  426. void Bank::scanrootdir(char *rootdir){
  427. //    printf("Scanning root dir:%s\n",rootdir);
  428.     DIR *dir=opendir(rootdir);
  429.     if (dir==NULL) return;
  430.  
  431.     const int maxdirsize=1000;
  432.     struct {
  433.     char dir[maxdirsize];
  434.     char name[maxdirsize];    
  435.     }bank;
  436.  
  437.     char *separator="/";
  438.     if (strlen(rootdir)) {
  439.     char tmp=rootdir[strlen(rootdir)-1];
  440.     if ((tmp=='/') || (tmp=='\\')) separator="";
  441.     };
  442.     
  443.     struct dirent *fn;
  444.     while ((fn=readdir(dir))){
  445.     const char *dirname=fn->d_name;
  446.     if (dirname[0]=='.') continue;
  447.     
  448.     snprintf(bank.dir,maxdirsize,"%s%s%s/",rootdir,separator,dirname);
  449.     snprintf(bank.name,maxdirsize,"%s",dirname);
  450.     //find out if the directory contains at least 1 instrument
  451.     bool isbank=false;
  452.     
  453.     DIR *d=opendir(bank.dir);
  454.     if (d==NULL) continue;
  455.     
  456.     struct dirent *fname;
  457.  
  458.     while((fname=readdir(d))){
  459.         if ((strstr(fname->d_name,INSTRUMENT_EXTENSION)!=NULL)||
  460.            (strstr(fname->d_name,FORCE_BANK_DIR_FILE)!=NULL)){
  461.         isbank=true;
  462.         break;//aici as putea pune in loc de break un update la un counter care imi arata nr. de instrumente din bank
  463.         };
  464.     };
  465.     
  466.     closedir(d);    
  467.     
  468.     if (isbank) {
  469.         int pos=-1;
  470.         for (int i=1;i<MAX_NUM_BANKS;i++){    //banks[0] e liber intotdeauna
  471.         if (banks[i].name==NULL) {
  472.             pos=i;
  473.             break;
  474.         };
  475.         };
  476.         
  477.         if (pos>=0) {
  478.         banks[pos].name=new char[maxdirsize];
  479.         banks[pos].dir=new char[maxdirsize];
  480.             snprintf(banks[pos].name,maxdirsize,"%s",bank.name);
  481.             snprintf(banks[pos].dir,maxdirsize,"%s",bank.dir);
  482.         };
  483.         
  484.     };
  485.     
  486.     };
  487.  
  488.     closedir(dir);
  489.     
  490. };
  491.  
  492. void Bank::clearbank(){
  493.     for (int i=0;i<BANK_SIZE;i++) deletefrombank(i);
  494.     if (dirname!=NULL) delete(dirname);
  495.     bankfiletitle=NULL;
  496.     dirname=NULL;
  497. };
  498.  
  499. int Bank::addtobank(int pos, const char *filename, const char* name){
  500.     if ((pos>=0)&&(pos<BANK_SIZE)){
  501.     if (ins[pos].used) pos=-1;//force it to find a new free position
  502.     } else if (pos>=BANK_SIZE) pos=-1;
  503.     
  504.     
  505.     if (pos<0) {//find a free position
  506.     for (int i=BANK_SIZE-1;i>=0;i--)
  507.         if (!ins[i].used) {
  508.         pos=i;
  509.         break;
  510.         };
  511.     
  512.     };
  513.     
  514.     if (pos<0) return (-1);//the bank is full
  515.  
  516.    // printf("%s   %d\n",filename,pos);
  517.  
  518.     deletefrombank(pos);
  519.     
  520.     ins[pos].used=true;
  521.     snprintf(ins[pos].name,PART_MAX_NAME_LEN,"%s",name);
  522.  
  523.     snprintf(tmpinsname[pos],PART_MAX_NAME_LEN+10," ");
  524.  
  525.     int len=strlen(filename)+1+strlen(dirname);
  526.     ins[pos].filename=new char[len+2];
  527.     ins[pos].filename[len+1]=0;
  528.     snprintf(ins[pos].filename,len+1,"%s/%s",dirname,filename);
  529.  
  530.     //see if PADsynth is used
  531.     if (config.cfg.CheckPADsynth){
  532.     XMLwrapper *xml=new XMLwrapper();
  533.     xml->checkfileinformation(ins[pos].filename);
  534.     
  535.     ins[pos].info.PADsynth_used=xml->information.PADsynth_used;
  536.     delete(xml);
  537.     } else ins[pos].info.PADsynth_used=false;
  538.     
  539.     return(0);
  540. };
  541.  
  542. bool Bank::isPADsynth_used(unsigned int ninstrument){
  543.     if (config.cfg.CheckPADsynth==0) return(0);
  544.     else return(ins[ninstrument].info.PADsynth_used);
  545. };
  546.  
  547.  
  548. void Bank::deletefrombank(int pos){
  549.     if ((pos<0)||(pos>=BANK_SIZE)) return;
  550.     ins[pos].used=false;
  551.     ZERO(ins[pos].name,PART_MAX_NAME_LEN+1);
  552.     if (ins[pos].filename!=NULL) {
  553.     delete (ins[pos].filename);
  554.     ins[pos].filename=NULL;
  555.     };
  556.     
  557.     ZERO(tmpinsname[pos],PART_MAX_NAME_LEN+20);
  558.     
  559. };
  560.  
  561.